package org.lex.swing.table;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.swing.table.AbstractTableModel;

/**
 * Create a read-only TableModel from Map<K,V>, use the Map.keySet() as first
 * column, and use Map.values() as second column.<br>
 * Optionaly, <b>column names</b> and<b>Comparator</b>can be specified.
 */
public class MapTableModel<K, V> extends AbstractTableModel {
	public static final String FIRST_COLUMN = "Name";
	public static final String SECOND_COLUMN = "Value";
	private String[] columnNames = null;
	private Class<?>[] columnClasses = null;
	private ArrayList<Map.Entry<K, V>> list = null;

	public MapTableModel(Map<K, V> map) {
		this(map, FIRST_COLUMN, SECOND_COLUMN);
	}

	public MapTableModel(Map<K, V> map, String firstColumn, String secondColumn) {
		this(map, firstColumn, secondColumn, null, null);
	}

	/**
	 * �������<br>
	 * 1. key==null && value!=null: ʹ��value<br>
	 * 2. key!=null: ʹ��key
	 * 
	 * @param map
	 * @param firstColumn
	 * @param secondColumn
	 * @param key
	 * @param value
	 */
	public MapTableModel(Map<K, V> map, String firstColumn, String secondColumn, final Comparator<K> key, final Comparator<V> value) {
		columnNames = new String[] { firstColumn, secondColumn };
		Set<Map.Entry<K, V>> entries = map.entrySet();
		this.list = new ArrayList<Map.Entry<K, V>>(entries.size());
		this.list.addAll(entries);
		Comparator<Map.Entry<K, V>> cp = null;
		if (null == key) {
			if (null != value)
				// key == null && value != null
				cp = new Comparator<Map.Entry<K, V>>() {
					@Override
					public int compare(Entry<K, V> o1, Entry<K, V> o2) {
						return value.compare(o1.getValue(), o2.getValue());
					}
				};
		} else {
			// key!= null
			cp = new Comparator<Map.Entry<K, V>>() {
				@Override
				public int compare(Entry<K, V> o1, Entry<K, V> o2) {
					return key.compare(o1.getKey(), o2.getKey());
				}
			};
		}
		if (null != cp)
			java.util.Collections.sort(list, cp);
		this.columnClasses = new Class<?>[2];
		if (list.isEmpty()) {
			columnClasses[0] = Object.class;
			columnClasses[1] = Object.class;
		} else {
			for (Map.Entry<K, V> e : list) {
				if (columnClasses[0] == null && e.getKey() != null)
					columnClasses[0] = e.getKey().getClass();
				if (columnClasses[1] == null && e.getValue() != null)
					columnClasses[1] = e.getValue().getClass();
				if (columnClasses[0] != null && columnClasses[1] != null)
					break;
			}
		}
	}

	@Override
	public Class<?> getColumnClass(int column) {
		return columnClasses[column];
	}

	@Override
	public String getColumnName(int column) {
		return columnNames[column];
	}

	@Override
	public int getColumnCount() {
		return 2;
	}

	@Override
	public int getRowCount() {
		return list.size();
	}

	@Override
	public Object getValueAt(int row, int column) {
		Map.Entry<K, V> entry = list.get(row);
		if (0 == column)
			return entry.getKey();
		else
			return entry.getValue();
	}
}
